// 引入必要的命名空间
using Microsoft.EntityFrameworkCore; // 提供Entity Framework Core功能
using UniversalAdmin.Application.DTOs; // 引入数据传输对象
using UniversalAdmin.Domain.Entities; // 引入领域实体
using UniversalAdmin.Infrastructure.Data.Contexts; // 引入数据库上下文
using UniversalAdmin.Infrastructure.Services; // 引入基础设施服务

// 定义服务命名空间
namespace UniversalAdmin.Application.Services
{
    // 实现IAuthService接口的认证服务类
    public class AuthService : IAuthService
    {
        // 声明数据库上下文
        private readonly ApplicationDbContext _db;
        // 声明JWT服务
        private readonly JwtService _jwtService;

        // 构造函数，依赖注入数据库上下文和JWT服务
        public AuthService(ApplicationDbContext db, JwtService jwtService)
        {
            _db = db;
            _jwtService = jwtService;
        }

        // 处理用户登录请求 - 性能优化版本
        public async Task<LoginResponseDto> LoginAsync(LoginDto loginDto)
        {
            // 手动验证传入的DTO
            if (string.IsNullOrWhiteSpace(loginDto.Username) || string.IsNullOrWhiteSpace(loginDto.Password))
                throw new ArgumentException("用户名和密码不能为空");

            // 查询用户是否存在 - 兼容UserName和Username两个字段
            var user = await _db.Users.FirstOrDefaultAsync(u =>
                u.UserName == loginDto.Username || u.Username == loginDto.Username);
            if (user == null)
                throw new UnauthorizedAccessException("用户名或密码错误");

            // 检查账户是否被锁定
            if (user.LockoutEnd.HasValue && user.LockoutEnd > DateTime.UtcNow)
            {
                var remainingMinutes = Math.Ceiling((user.LockoutEnd.Value - DateTime.UtcNow).TotalMinutes);
                throw new UnauthorizedAccessException($"账户已锁定，请{remainingMinutes}分钟后再试");
            }

            // 验证密码是否正确
            if (!BCrypt.Net.BCrypt.Verify(loginDto.Password, user.PasswordHash))
            {
                // 增加登录尝试次数
                user.LoginAttempts++;
                // 如果尝试次数超过5次，锁定账户30分钟
                if (user.LoginAttempts >= 5)
                {
                    user.LockoutEnd = DateTime.UtcNow.AddMinutes(30);
                }
                // 合并保存：只在失败时保存一次，减少数据库调用
                await _db.SaveChangesAsync();

                if (user.LoginAttempts >= 5)
                {
                    throw new UnauthorizedAccessException("登录失败次数过多，账户已锁定30分钟");
                }
                var remainingAttempts = 5 - user.LoginAttempts;
                throw new UnauthorizedAccessException($"用户名或密码错误，还剩{remainingAttempts}次尝试机会");
            }

            // 合并更新操作：一次性更新所有字段，减少数据库调用
            user.LoginAttempts = 0;
            user.LockoutEnd = null;
            user.LastLoginAt = DateTime.UtcNow;
            await _db.SaveChangesAsync();

            // 生成JWT令牌
            var token = _jwtService.GenerateToken(user, loginDto.RememberMe);
            // 返回登录响应
            return new LoginResponseDto
            {
                UserId = user.Id,
                Token = token,
                Username = user.UserName ?? user.Username, // 优先使用IdentityUser的UserName
                Email = user.Email ?? "",
                Last = user.PasswordSalt
            };
        }

        // 处理用户注册请求
        public async Task<bool> RegisterAsync(RegisterDto registerDto)
        {
            // 手动验证传入的DTO
            if (string.IsNullOrWhiteSpace(registerDto.Username) || string.IsNullOrWhiteSpace(registerDto.Password) || string.IsNullOrWhiteSpace(registerDto.Email))
                throw new ArgumentException("用户名、密码和邮箱不能为空");

            // 检查用户名是否已存在 - 兼容UserName和Username两个字段
            if (await _db.Users.AnyAsync(u => u.UserName == registerDto.Username || u.Username == registerDto.Username))
                throw new ArgumentException("用户名已存在");

            // 检查邮箱是否已被注册
            if (await _db.Users.AnyAsync(u => u.Email == registerDto.Email))
                throw new ArgumentException("邮箱已被注册");

            // 检查手机号是否已被注册
            if (!string.IsNullOrWhiteSpace(registerDto.Phone) && await _db.Users.AnyAsync(u => u.PhoneNumber == registerDto.Phone))
                throw new ArgumentException("手机号已被注册");

            // 生成盐和哈希值
            string salt = BCrypt.Net.BCrypt.GenerateSalt();
            string passwordHash = BCrypt.Net.BCrypt.HashPassword(registerDto.Password, salt);

            // 创建新用户
            var user = new User
            {
                UserName = registerDto.Username,    // IdentityUser字段
                Username = registerDto.Username,    // 自定义字段（保持兼容性）
                Email = registerDto.Email,
                PhoneNumber = registerDto.Phone, // 保存手机号
                PasswordHash = passwordHash,
                PasswordSalt = salt, // 存储盐
                LastLoginAt = DateTime.UtcNow // 设置初始登录时间为当前时间
            };
            // 添加用户到数据库
            _db.Users.Add(user);
            await _db.SaveChangesAsync();
            return true;
        }

        // 处理用户注销请求
        public async Task LogoutAsync(string token)
        {
            // 检查Token是否为空
            if (string.IsNullOrEmpty(token))
                throw new UnauthorizedAccessException("无效的Token格式");

            // 将Token加入黑名单
            _db.TokenBlacklist.Add(new TokenBlacklist
            {
                Token = token,
                ExpireAt = DateTime.UtcNow.AddDays(7)
            });
            // 保存更改
            await _db.SaveChangesAsync();
        }
    }
}